Portfolio performance and key metrics¶

Code written by Vala "Valatility" Zeinali and Lev "l3v" Thierbach¶

In [1]:
import yfinance as yf
import numpy as np
import pandas as pd
from pandas_datareader import data as pdr
from matplotlib import pyplot as plt
import plotly.graph_objects as go
import warnings
import statistics as stats
import empyrical as emp
warnings.filterwarnings("ignore")
In [2]:
start_date = "2023-01-05"
end_date = "2023-12-12"
In [3]:
tickers = ["ARGT","AVTR","HCC","DHR","TMF","VZ","USO","TTWO","SHY","MBB","GLD","EWZ","EA","CTLT","GEHC","SPY"]
In [4]:
wts = [
 -0.07
,-0.01
,0.03
,0.01
,0.24
,0.02
,0.23
,0.01
,0.10
,0.13
,-0.07
,0.07
,-0.01
,0.01
,0.03
,0.000
]
In [5]:
yf.pdr_override()

price_data = pdr.get_data_yahoo(tickers,
                               start = start_date,
                               end = end_date)
[*********************100%%**********************]  16 of 16 completed
In [6]:
price_data = price_data['Adj Close']
In [7]:
ret_data = price_data.pct_change()[1:]
In [8]:
weighted_returns = (wts * ret_data)
In [9]:
weighted_returns = weighted_returns.reset_index()
weighted_returns.head()
Out[9]:
Date ARGT AVTR CTLT DHR EA EWZ GEHC GLD HCC MBB SHY SPY TMF TTWO USO VZ
0 2023-01-06 -0.001979 0.000276 0.000968 -0.000107 -0.001521 0.000771 -0.000195 0.000187 0.003746 0.001680 -0.000267 0.001605 -0.000543 -0.000114 0.000023 0.0
1 2023-01-09 -0.001120 -0.000294 0.000327 0.000101 0.000542 -0.000148 -0.003316 0.000022 -0.002917 0.000384 -0.000069 -0.000040 -0.000146 0.000033 0.000486 -0.0
2 2023-01-10 -0.000445 -0.000392 -0.000050 0.000464 -0.000290 0.000520 0.007522 0.000037 0.001131 -0.000533 0.000060 0.000491 0.000475 0.000041 0.000009 0.0
3 2023-01-11 -0.001537 -0.000331 0.000848 0.000259 0.004045 0.000458 0.019128 -0.000007 0.000206 0.000906 -0.000060 0.000885 -0.000463 -0.000026 0.000979 -0.0
4 2023-01-12 -0.002049 0.000023 -0.000067 -0.000055 0.000590 0.000170 0.002336 0.000116 -0.000675 0.000913 -0.000154 0.000255 -0.000576 -0.000092 0.000247 0.0
In [10]:
# Calculate portfolio returns
port_ret = weighted_returns.drop("Date", axis=1).sum(axis=1)
# axis =1 tells pandas we want to add
In [11]:
cumulative_ret = ((port_ret + 1).cumprod()) - 1
cumulative_ret_single_tick = (((ret_data + 1).cumprod()) - 1)*100
In [12]:
MHF = cumulative_ret
SPY = ((ret_data["SPY"] + 1).cumprod()) - 1
In [13]:
fig1 = go.Figure() # go object

fig1.add_trace(go.Scatter(x=weighted_returns["Date"],y=MHF*100, name='Valatility Return',
                         line=dict(color='royalblue', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=SPY*100, name='SPY',
                        line=dict(color='green', width=3,)))

# Edit the layout
fig1.update_layout(title=f'Mock Hedgefund {(MHF.tail(1).values *100).round(2)}% vs SPY {(SPY.tail(1).values *100).round(2)}% - 2023',
                   xaxis_title='Year',
                   yaxis_title='Cumulative Return (%)', width=1000, height=800,)
fig1.show()
In [14]:
fig1 = go.Figure() # go object

fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick['ARGT'], name='ARGT',
                        line=dict(color='green', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick['AVTR'], name='AVTR',
                        line=dict(color='red', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick['HCC'], name='HCC',
                        line=dict(color='blue', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick['DHR'], name='DHR',
                        line=dict(color='brown', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick['TMF'], name='TMF',
                        line=dict(color='yellow', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick['VZ'], name='VZ',
                        line=dict(color='orange', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick['USO'], name='USO',
                        line=dict(color='pink', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick['TTWO'], name='TTWO',
                        line=dict(color='purple', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick['SHY'], name='SHY',
                        line=dict(color='black', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick['MBB'], name='MBB',
                        line=dict(color='tan', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick['GLD'], name='GLD',
                        line=dict(color='goldenrod', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick['EWZ'], name='EWZ',
                        line=dict(color='magenta', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick['EA'], name='EA',
                        line=dict(color='darkturquoise', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick['CTLT'], name='CTLT',
                        line=dict(color='aquamarine', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick['GEHC'], name='GEHC',
                        line=dict(color='aquamarine', width=3,)))


fig1.update_layout(title=f'Time series of all assets| Cumulative Return - 2023 (%)',
                   xaxis_title='Year',
                   yaxis_title='Cumulative Return)(%)', width=1000, height=800,)

fig1.show()
In [15]:
Alpha = (MHF.tail(1).values *100).round(2) - (SPY.tail(1).values *100).round(2)
In [16]:
Beta = stats.covariance(MHF, SPY) / stats.variance(SPY)
In [17]:
# Calculate the Sharpe Ratio
sharpe_ratio = np.mean(MHF) / np.std(MHF)

# Annualize the Sharpe Ratio
annual_factor = np.sqrt(252)  # Use 252 for daily returns, 52 for weekly returns, 12 for monthly returns
sharpe_ratio_annu = sharpe_ratio * annual_factor

Alpha for all assets

In [18]:
alpha_values = []
asset_names = []


# Calculate Alpha for each asset
for asset in tickers:
    asset_returns = ret_data[asset]
    
    risk_free_rate = 0.00 
    excess_return = asset_returns - risk_free_rate
    alpha = (excess_return.mean() * 252) * 100  # % Annualized Alpha
    asset_names.append(asset)
    alpha_values.append(alpha)

# Create a df to hold Asset and Alpha values
alpha_df = pd.DataFrame({'Asset': asset_names, 'Alpha': alpha_values})

Beta for all assets

In [19]:
beta_values = []

# Calculate Beta for each asset
for asset in tickers:
        asset_returns = ret_data[asset]
        covar = stats.covariance(asset_returns, SPY)
        var = stats.variance(SPY)
        beta = covar / var
        beta_values.append(beta)
    

# Create a df to hold Asset and Beta values
beta_df = pd.DataFrame({'Asset': tickers, 'Beta': beta_values})

Plot Alpha

In [20]:
fig = go.Figure()

fig.add_trace(go.Scatter(
    x=alpha_values, y=asset_names,
    name='Alpha',
    mode='markers',
    marker_color= alpha_values
    
    )
)

fig.update_layout(title='Alpha| Asset vs. Benchmark(SPY) for Portfolio Assets - 2023',
                  yaxis_title='Ticker', width=1000, height=800,
                  xaxis_title='Alpha Values')
fig.update_traces(mode='markers', marker_line_width=1, marker_size=15)
                
fig.show()

Plot Beta

In [21]:
fig = go.Figure()

fig.add_trace(go.Scatter(
    x=beta_values, y=tickers,
    name='Beta',
    mode='markers',
    marker_color= beta_values
    
    )
)

fig.update_layout(title='Beta| Asset vs. Benchmark(SPY) for Portfolio Assets - 2023',
                 yaxis_title='Ticker', width=1000, height=800,
                  xaxis_title='Beta Values')
fig.update_traces(mode='markers', marker_line_width=1, marker_size=15)
fig.show()

Metrics

In [22]:
print(f'Annualized Sharpe Ratio (2023): {round(sharpe_ratio_annu, 2)}%')
Annualized Sharpe Ratio (2023): 42.58%
In [23]:
print(f'2023 Yearly Alpha: {round(Alpha[0], 2)}%')
2023 Yearly Alpha: -7.54%
In [24]:
print(f'2023 Yearly Beta: {round(Beta, 2)}')
2023 Yearly Beta: 0.35

Equities¶

In [25]:
eqticks = ["AVTR","HCC","VZ","TTWO","EA","CTLT","GEHC","SPY"]
In [26]:
yf.pdr_override()

price_data_eq1 = pdr.get_data_yahoo(eqticks,
                               start = start_date,
                               end = end_date)
[*********************100%%**********************]  8 of 8 completed
In [27]:
price_data_eq = price_data_eq1['Adj Close']
In [28]:
wts_eq = [
-0.01
,0.3
,0.02
,0.01
,-0.01
,0.01
,0.03
,0.000
]
In [29]:
ret_data_eq = price_data_eq.pct_change()[1:]
In [30]:
weighted_returns_eq = (wts_eq * ret_data_eq)
In [31]:
weighted_returns_eq = weighted_returns_eq.reset_index()
In [32]:
# Calculate portfolio equities returns
port_ret_eq = weighted_returns_eq.drop("Date", axis=1).sum(axis=1)
In [33]:
cumulative_ret_eq = ((port_ret_eq + 1).cumprod()) - 1
cumulative_ret_single_tick_eq = (((ret_data_eq + 1).cumprod()) - 1)*100
In [34]:
MHF_EQ = cumulative_ret_eq
In [35]:
fig1 = go.Figure() # go object

fig1.add_trace(go.Scatter(x=weighted_returns_eq["Date"],y=MHF_EQ*100, name='Equites Return',
                         line=dict(color='royalblue', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=SPY*100, name='SPY',
                        line=dict(color='green', width=3,)))

# Edit the layout
fig1.update_layout(title=f'Mock Hedge fund| Equities {(MHF_EQ.tail(1).values *100).round(2)}% vs SPY {(SPY.tail(1).values *100).round(2)}% - 2023',
                   xaxis_title='Year',
                   yaxis_title='Cumulative Return (%)', width=1000, height=800,)
fig1.show()
In [36]:
fig1 = go.Figure() # go object

fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick_eq['AVTR'], name='AVTR',
                        line=dict(color='green', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick_eq['HCC'], name='HCC',
                        line=dict(color='red', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick_eq['VZ'], name='VT',
                        line=dict(color='blue', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick_eq['TTWO'], name='TTWO',
                        line=dict(color='brown', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick_eq['EA'], name='EA',
                        line=dict(color='yellow', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick_eq['CTLT'], name='CTLT',
                        line=dict(color='orange', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick_eq['GEHC'], name='GEHC',
                        line=dict(color='orange', width=3,)))
fig1.update_layout(title=f'Time series of Equties| Cumulative Return - 2023 (%)',
                   xaxis_title='Year',
                   yaxis_title='Cumulative Return)(%)', width=1000, height=800,)

fig1.show()
In [37]:
Alpha_EQ = (MHF_EQ.tail(1).values *100).round(2) - (SPY.tail(1).values *100).round(2)
In [38]:
Beta_EQ = stats.covariance(MHF_EQ, SPY) / stats.variance(SPY)
In [39]:
# Calculate the Sharpe Ratio for EQ
sharpe_ratio_EQ = np.mean(MHF_EQ) / np.std(MHF_EQ)

# Annualize the Sharpe 
annual_factor_EQ = np.sqrt(252)  
sharpe_ratio_annu_EQ = sharpe_ratio_EQ * annual_factor_EQ
In [40]:
alpha_values_eq = []
asset_names_eq = []


# Calculate Alpha for each equitie
for asset_eq in eqticks:
    asset_returns_eq = ret_data_eq[asset_eq]
    
    risk_free_rate = 0.00 
    excess_return_eq = asset_returns_eq - risk_free_rate
    alpha_eq = (excess_return_eq.mean() * 252) * 100  # % Annualized Alpha
    asset_names_eq.append(asset_eq)
    alpha_values_eq.append(alpha_eq)

# Create a df to hold Asset names and Alpha values
alpha_df_eq = pd.DataFrame({'Asset': asset_names_eq, 'Alpha': alpha_values_eq})
In [41]:
beta_values_eq = []

# Calculate Beta for each asset
for asset_eq in eqticks:
        asset_returns_eq = ret_data_eq[asset_eq]
        covar_eq = stats.covariance(asset_returns_eq, SPY)
        var_eq = stats.variance(SPY)
        beta_eq = covar_eq / var_eq
        beta_values_eq.append(beta_eq)
    

# Create a df to hold Asset and Beta values
beta_df_eq = pd.DataFrame({'Asset': eqticks, 'Beta': beta_values_eq})
In [42]:
fig = go.Figure()

fig.add_trace(go.Scatter(
    x=alpha_values_eq, y=asset_names_eq,
    name='Alpha',
    mode='markers',
    marker_color= alpha_values_eq
    
    )
)

fig.update_layout(title='Alpha| Equities vs. Benchmark(SPY) for Portfolio Assets - 2023',
                  yaxis_title='Ticker', width=1000, height=800,
                  xaxis_title='Alpha Values')
fig.update_traces(mode='markers', marker_line_width=1, marker_size=15)
                
fig.show()
In [43]:
fig = go.Figure()

fig.add_trace(go.Scatter(
    x=beta_values_eq, y=eqticks,
    name='Beta',
    mode='markers',
    marker_color= beta_values_eq
    
    )
)

fig.update_layout(title='Beta| Equities vs. Benchmark(SPY) for Portfolio Assets - 2023',
                 yaxis_title='Ticker', width=1000, height=800,
                  xaxis_title='Beta Values')
fig.update_traces(mode='markers', marker_line_width=1, marker_size=15)
fig.show()
In [44]:
print(f'Annualized Equities Sharpe Ratio (2023): {round(sharpe_ratio_annu_EQ, 2)}%')
Annualized Equities Sharpe Ratio (2023): 16.62%
In [45]:
print(f'2023 Yearly Equities Alpha: {round(Alpha_EQ[0], 2)}%')
2023 Yearly Equities Alpha: -10.69%
In [46]:
print(f'2023 Yearly Equities Beta: {round(Beta_EQ, 2)}')
2023 Yearly Equities Beta: -0.24

Global Macro¶

In [47]:
tickers_gm = ["ARGT","TMF","USO","SHY","MBB","GLD","EWZ","SPY"]
In [48]:
wts_gm = [
 -0.07
,0.24
,-0.23
,0.10
,0.13
,-0.07
,0.07
,0.000
]
In [49]:
yf.pdr_override()

price_data_gm1 = pdr.get_data_yahoo(tickers_gm,
                               start = start_date,
                               end = end_date)
[*********************100%%**********************]  8 of 8 completed
In [50]:
price_data_gm = price_data_gm1['Adj Close']
In [51]:
ret_data_gm = price_data_gm.pct_change()[1:]
In [52]:
weighted_returns_gm = (wts_gm * ret_data_gm)
In [53]:
weighted_returns_gm = weighted_returns_gm.reset_index()
In [54]:
# Calculate portfolio macro returns
port_ret_gm = weighted_returns_gm.drop("Date", axis=1).sum(axis=1)
In [55]:
cumulative_ret_gm = ((port_ret_gm + 1).cumprod()) - 1
cumulative_ret_single_tick_gm = (((ret_data_gm + 1).cumprod()) - 1)*100
In [56]:
MHF_GM = cumulative_ret_gm
In [57]:
fig1 = go.Figure() # go object

fig1.add_trace(go.Scatter(x=weighted_returns_gm["Date"],y=MHF_GM*100, name='Macro Return',
                         line=dict(color='royalblue', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=SPY*100, name='SPY',
                        line=dict(color='green', width=3,)))

# Edit the layout
fig1.update_layout(title=f'Mock Hedge fund| Global Macro {(MHF_GM.tail(1).values *100).round(2)}% vs SPY {(SPY.tail(1).values *100).round(2)}% - 2023',
                   xaxis_title='Year',
                   yaxis_title='Cumulative Return (%)', width=1000, height=800,)
fig1.show()
In [58]:
fig1 = go.Figure() # go object

fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick_gm['ARGT'], name='ARGT',
                        line=dict(color='green', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick_gm['TMF'], name='TMF',
                        line=dict(color='red', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick_gm['USO'], name='USO',
                        line=dict(color='blue', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick_gm['SHY'], name='SHY',
                        line=dict(color='brown', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick_gm['MBB'], name='MBB',
                        line=dict(color='yellow', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick_gm['GLD'], name='GLD',
                        line=dict(color='orange', width=3,)))
fig1.add_trace(go.Scatter(x=weighted_returns["Date"], y=cumulative_ret_single_tick_gm['EWZ'], name='EWZ',
                        line=dict(color='orange', width=3,)))

fig1.update_layout(title=f'Time series of Global Macro| Cumulative Return - 2023 (%)',
                   xaxis_title='Year',
                   yaxis_title='Cumulative Return)(%)', width=1000, height=800,)

fig1.show()
In [59]:
Alpha_GM = (MHF_GM.tail(1).values *100).round(2) - (SPY.tail(1).values *100).round(2)
In [60]:
Beta_GM = stats.covariance(MHF_GM, SPY) / stats.variance(SPY)
In [61]:
# Calculate the Sharpe Ratio for Macro
sharpe_ratio_GM = np.mean(MHF_GM) / np.std(MHF_GM)

# Annualize the Sharpe 
annual_factor_GM = np.sqrt(252)  
sharpe_ratio_annu_GM = sharpe_ratio_GM * annual_factor_GM
In [62]:
alpha_values_gm = []
asset_names_gm = []


# Calculate Alpha for each equitie
for asset_gm in tickers_gm:
    asset_returns_gm = ret_data_gm[asset_gm]
    
    risk_free_rate = 0.00 
    excess_return_gm = asset_returns_gm - risk_free_rate
    alpha_gm = (excess_return_gm.mean() * 252) * 100  # % Annualized Alpha
    asset_names_gm.append(asset_gm)
    alpha_values_gm.append(alpha_gm)

# Create a df to hold Asset names and Alpha values
alpha_df_gm = pd.DataFrame({'Asset': asset_names_gm, 'Alpha': alpha_values_gm})
In [63]:
beta_values_gm = []

# Calculate Beta for each asset
for asset_gm in tickers_gm:
        asset_returns_gm = ret_data_gm[asset_gm]
        covar_gm = stats.covariance(asset_returns_gm, SPY)
        var_gm = stats.variance(SPY)
        beta_gm = covar_gm / var_gm
        beta_values_gm.append(beta_gm)
    

# Create a df to hold Asset and Beta values
beta_df_gm = pd.DataFrame({'Asset': tickers_gm, 'Beta': beta_values_gm})
In [64]:
fig = go.Figure()

fig.add_trace(go.Scatter(
    x=alpha_values_gm, y=asset_names_gm,
    name='Alpha',
    mode='markers',
    marker_color= alpha_values_gm
    
    )
)

fig.update_layout(title='Alpha| Global Macro vs. Benchmark(SPY) for Portfolio Assets - 2023',
                  yaxis_title='Ticker', width=1000, height=800,
                  xaxis_title='Alpha Values')
fig.update_traces(mode='markers', marker_line_width=1, marker_size=15)
                
fig.show()
In [65]:
fig = go.Figure()

fig.add_trace(go.Scatter(
    x=beta_values_gm, y=tickers_gm,
    name='Beta',
    mode='markers',
    marker_color= beta_values_gm
    
    )
)

fig.update_layout(title='Beta| Equities vs. Benchmark(SPY) for Portfolio Assets - 2023',
                 yaxis_title='Ticker', width=1000, height=800,
                  xaxis_title='Beta Values')
fig.update_traces(mode='markers', marker_line_width=1, marker_size=15)
fig.show()
In [66]:
print(f'Annualized Global Macro Sharpe Ratio (2023): {round(sharpe_ratio_annu_GM, 2)}%')
Annualized Global Macro Sharpe Ratio (2023): -12.85%
In [67]:
print(f'2023 Yearly Global Macro Alpha: {round(Alpha_GM[0], 2)}%')
2023 Yearly Global Macro Alpha: -16.83%
In [68]:
print(f'2023 Yearly Global Macro Beta: {round(Beta_GM, 2)}')
2023 Yearly Global Macro Beta: 0.02